package com.xbongbong.saas.analytical.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.ConfigConstant;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.FormDataValidateDataHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.help.SerialNoHelp;
import com.xbongbong.paas.help.team.TeamUserHelp;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.pojo.AddMuchFieldPojo;
import com.xbongbong.paas.pojo.dto.AddBatchDTO;
import com.xbongbong.paas.pojo.dto.AggSumDTO;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataUpdateGetDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.vo.AggSumVO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.domain.entity.FormConfigEntity;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ContractErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.PaymentErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ImportErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.fund.enums.ModelTypeEnum;
import com.xbongbong.pro.enums.fund.enums.PeriodTypeEnum;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.pro.fundset.pojo.PeriodFilterPojo;
import com.xbongbong.pro.team.TeamAfterVerifyDTO;
import com.xbongbong.pro.user.pojo.ReturnUserAndDepartmentPojo;
import com.xbongbong.saas.analytical.SaasValidateAnalyticalService;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentEntityExt;
import com.xbongbong.saas.enums.FormConfigEnum;
import com.xbongbong.saas.enums.LinkAddOperationFlagEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.PaymentEnum;
import com.xbongbong.saas.enums.dictionary.PaymentStatusEnum;
import com.xbongbong.saas.help.FundHelp;
import com.xbongbong.saas.help.SaasDataInitHelp;
import com.xbongbong.saas.help.SaveFormatHelp;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.FormConfigModel;
import com.xbongbong.saas.model.FundSetModel;
import com.xbongbong.saas.model.PaymentModel;
import com.xbongbong.saas.service.toolbox.help.FundMoneyHelp;
import com.xbongbong.saas.service.toolbox.help.FundSetHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.util.ValidateUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author 吴峰
 * @date 2021/07/15 14:28
 */
@Service("paymentAnalyticalServiceImpl")
public class PaymentValidateAnalyticalServiceImpl implements SaasValidateAnalyticalService {

    private static final Logger LOG = LoggerFactory.getLogger(PaymentValidateAnalyticalServiceImpl.class);
    @Resource
    private PaymentModel paymentModel;
    @Resource
    private ContractModel contractModel;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private EsHelper esHelper;
    @Resource
    private FormDataValidateDataHelp formDataValidateDataHelp;
    @Resource
    private FormConfigModel formConfigModel;
    @Resource
    private FundMoneyHelp fundMoneyHelp;
    @Resource
    private FundSetModel fundSetModel;
    @Resource
    private FundSetHelp fundSetHelp;
    @Resource
    private FundHelp fundHelp;
    @Resource
    private SerialNoHelp serialNoHelp;
    @Resource
    private TeamUserHelp teamUserHelp;


    @Override
    public List<Integer> type() {
        return Arrays.asList(XbbRefTypeEnum.PAYMENT.getCode());
    }
    @Override
    public void analyticalData(ValidateDataDTO validateDataDTO) throws XbbException {
        beforeSave(validateDataDTO);
        teamUserHelp.beforeVerifyUserTeam(validateDataDTO);
    }

    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException{
        try {
            JSONObject data = validateDataDTO.getData();
            // 移除币种数据
            data.remove(PaymentEnum.UNIT.getAttr());
            PaymentEntityExt paymentEntityExt = new PaymentEntityExt();
            Long contractId = null;
            List<Long> idIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if ( validateDataDTO.getDataId() != null ) {
                paymentEntityExt = paymentModel.getByKey(validateDataDTO.getDataId(), validateDataDTO.getCorpid());
                idIn.add(validateDataDTO.getDataId());
            }
            SaveFormatHelp.formatLinkBusiness4SaveByArray(data, PaymentEnum.CUSTOMER.getAttr(), PaymentEnum.CUSTOMER_LINK_TEXT.getAttr(), PaymentEnum.CUSTOMER_LINK_TEXT.getFieldType());
            SaveFormatHelp.formatLinkBusiness4SaveByArray(data, PaymentEnum.CONTRACT.getAttr(), PaymentEnum.CONTRACT_LINK_TEXT.getAttr(), PaymentEnum.CONTRACT_LINK_TEXT.getFieldType());
            SaveFormatHelp.formatLinkBusiness4SaveByArray(data, PaymentEnum.RECEIVABLES_ORIGIN_ID.getAttr(),PaymentEnum.RECEIVABLES_ORIGIN_LINK_TEXT.getAttr(),PaymentEnum.RECEIVABLES_ORIGIN_LINK_TEXT.getFieldType());
            SaveFormatHelp.formatLinkBusiness4SaveByArray(data, PaymentEnum.SOURCE.getAttr(), PaymentEnum.SOURCE_LINK_TEXT.getAttr(),PaymentEnum.SOURCE_LINK_TEXT.getFieldType());
            Long originId  = FastJsonHelper.getLongOrDefaultFromFormData(data,PaymentEnum.RECEIVABLES_ORIGIN_ID.getAttr(),0L);
            contractId = FastJsonHelper.getLongOrDefaultFromFormData(data, PaymentEnum.CONTRACT.getAttr(), 0L);
            ContractEntityExt contractEntityExt = contractModel.getByKey(contractId, validateDataDTO.getCorpid());
            if (Objects.isNull(contractEntityExt)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
            }
            FormDataUpdateGetDTO formDataUpdateGetDTO = new FormDataUpdateGetDTO();
            BeanUtil.copyProperties(validateDataDTO,formDataUpdateGetDTO);
            //已生成的应收金额
            Double receivableAmount = beforeSaveGetTotalAmount(validateDataDTO.getCorpid(), contractId, idIn, true, formDataUpdateGetDTO);
            Double amount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, PaymentEnum.AMOUNT.getAttr(), 0D);
            //合同的金额
            Double contractAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(contractEntityExt.getData(), ContractEnum.AMOUNT.getAttr(), 0D);

            //红冲时需要控制填写金额不能大于原始应收款金额 和 红冲应收款逻辑
            if(originId > 0L && Objects.isNull(validateDataDTO.getDataId())){
                paymentEntityExt = paymentModel.getByKey(originId,validateDataDTO.getCorpid());
                if (Objects.isNull(paymentEntityExt)) {
                    throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208063);
                }
                JSONObject originData = paymentEntityExt.getData();
                Double unAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(originData,PaymentEnum.UN_AMOUNT.getAttr(),0D);
                if(Objects.equals(unAmount,BasicConstant.ZERO_DOUBLE)){
                    throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208062);
                }
                if (amount <= 0) {
                    throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208065);
                }
                if(unAmount < amount){
                    throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208066);
                }
                //API传过来的text_60(来源单据是空的)，所以这边需要重新赋值
                if (Objects.isNull(data.get(PaymentEnum.SOURCE.getAttr()))) {
                    data.put(PaymentEnum.SOURCE.getAttr(), FastJsonHelper.getLongFromFormData(originData, PaymentEnum.SOURCE.getAttr()));
                    data.put(PaymentEnum.SOURCE_LINK_TEXT.getAttr(), FastJsonHelper.getLongOrDefaultFromFormData(originData, PaymentEnum.SOURCE_LINK_TEXT.getAttr(), 0L));
                }
                data.put(PaymentEnum.RECEIVABLE_IS_RED.getAttr(),BasicConstant.ONE);
                data.put(PaymentEnum.STATUS.getAttr(),PaymentStatusEnum.RED_RECEIVABLES.getCode());
                data.put(PaymentEnum.AMOUNT.getAttr(),-amount);
                data.put(PaymentEnum.RECEIVABLE_PERIOD.getAttr(),FastJsonHelper.getStringOrDefaultFromFormData(originData,PaymentEnum.RECEIVABLE_PERIOD.getAttr(),""));
                data.put(PaymentEnum.GENERATION_DATE.getAttr(),FastJsonHelper.getLongOrDefaultFromFormData(originData,PaymentEnum.GENERATION_DATE.getAttr(),0L));
                data.put(PaymentEnum.ESTIMATE_TIME.getAttr(),FastJsonHelper.getLongOrDefaultFromFormData(originData,PaymentEnum.ESTIMATE_TIME.getAttr(),0L));
                data.put(PaymentEnum.UN_AMOUNT.getAttr(), 0);
                data.put(PaymentEnum.REAL_AMOUNT.getAttr(), 0);
                amount = -amount;
            }else {
                //对编辑，新建导入，覆盖导入应收款，应收金额必须大于0
                if (amount <= 0 && (Objects.isNull(originId) || Objects.equals(BasicConstant.ZERO_LONG, originId))) {
                    throw new XbbException(ImportErrorCodeEnum.API_ERROR_235030);
                }
                //对普通应收款的处理,包括普通应收款编辑、普通应收款导入、普通应收款覆盖导入
                if (Arith.sub(Arith.add(receivableAmount, amount), contractAmount) > ConfigConstant.amountAccuracy) {
                    throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208002);
                }
                Long nowModelType = fundSetModel.getModelType(validateDataDTO.getCorpid(),XbbRefTypeEnum.CRM);
                //在新增的时候才会判断，非手动创建的时候才会提示报错信息
                if (!Objects.equals(nowModelType, ModelTypeEnum.PLAN.getCode()) && Objects.isNull(validateDataDTO.getDataId())) {
                    throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208079);
                }
                Long generationDate = 0L;
                Long estimateTime = 0L;
                PeriodFilterPojo periodFilter = new PeriodFilterPojo();
                //因为除了新增还有普通导入需要下面计算这些金额，其它编辑还有覆盖导入(dataId != null && isImport == 1)不需要计算这些东西
                if (Objects.isNull(validateDataDTO.getDataId())) {
                    //普通应收款新建，应收生成日期是当天，应收账期 = 预计回款日期 - 应收生成日期
                    periodFilter = fundSetHelp.getPeriodFilter4Payment(validateDataDTO.getCorpid(), FastJsonHelper.getLongOrDefaultFromFormData(data,PaymentEnum.ESTIMATE_TIME.getAttr(),0L),
                            null, null, null);
                    if (Objects.equals(validateDataDTO.getIsImport(), 1)) {
                        //导入逻辑
                        if (!Objects.equals(data.getString(PaymentEnum.STATUS.getAttr()), PaymentStatusEnum.UN_RECEIVABLES.getCode())) {
                            throw new XbbException(ImportErrorCodeEnum.API_ERROR_235027);
                        }
                        data.put(PaymentEnum.UN_AMOUNT.getAttr(), amount);
                        data.put(PaymentEnum.REAL_AMOUNT.getAttr(), 0);
                    }else {
                        if (Objects.equals(paymentEntityExt.getData().getString(PaymentEnum.STATUS.getAttr()), PaymentStatusEnum.UN_RECEIVABLES.getCode())) {
                            data.put(PaymentEnum.UN_AMOUNT.getAttr(), amount);
                            data.put(PaymentEnum.REAL_AMOUNT.getAttr(), 0);
                        }
                    }
                    data.put(PaymentEnum.GENERATION_DATE.getAttr(), periodFilter.getGenerationTime());
                }else if (Objects.nonNull(paymentEntityExt) && Objects.nonNull(validateDataDTO.getDataId()) && Objects.equals(validateDataDTO.getIsImport(), 1)) {
                    //获得创建应收款的模式
                    Long modelType = paymentEntityExt.getSysLong10();
                    FieldAttrEntity fieldAttrEntity = validateDataDTO.getExplainMap().get(PaymentEnum.AMOUNT.getAttr());
                    //覆盖导入的时候需要移除一些不能编辑的系统字段
                    removeUnCoverImportValue(data, paymentEntityExt.getData(),validateDataDTO.getBusinessType(), nowModelType, fieldAttrEntity, modelType);
                    generationDate = data.getLongValue(PaymentEnum.GENERATION_DATE.getAttr());
                    estimateTime = data.getLong(PaymentEnum.ESTIMATE_TIME.getAttr());
                    periodFilter = fundSetHelp.getPeriodFilter4Payment(validateDataDTO.getCorpid(), estimateTime,
                            null, null, generationDate);
                }else if (Objects.nonNull(paymentEntityExt) && Objects.nonNull(validateDataDTO.getDataId())) {
                    //编辑
                    generationDate = data.getLongValue(PaymentEnum.GENERATION_DATE.getAttr());
                    estimateTime = data.getLong(PaymentEnum.ESTIMATE_TIME.getAttr());
                    periodFilter = fundSetHelp.getPeriodFilter4Payment(validateDataDTO.getCorpid(), estimateTime,
                            null, null, generationDate);
                }
                //编辑应收款金额时,未收金额需要改为和应收金额一致
                Boolean isUnReceivables = PaymentStatusEnum.checkPaymentEditStatus(data.getString(PaymentEnum.STATUS.getAttr()));
                Double invoiceAmount = FastJsonHelper.getDoubleOrDefaultFromFormData(data, PaymentEnum.INVOICE_AMOUNT.getAttr(), BasicConstant.ZERO_DOUBLE);
                Long modelType = paymentEntityExt.getSysLong10();
                boolean flag = isUnReceivables
                        && Objects.equals(nowModelType, ModelTypeEnum.PLAN.getCode())
                        && (Objects.nonNull(modelType) && Objects.equals(modelType, ModelTypeEnum.PLAN.getCode()))
                        && Objects.equals(invoiceAmount,BasicConstant.ZERO_DOUBLE);
                if(flag){
                    data.put(PaymentEnum.UN_AMOUNT.getAttr(), amount);
                }
                JSONObject generationJson = new JSONObject();
                generationJson.put(BasicConstant.TYPE, PeriodTypeEnum.DAY_AFTER.getCode());
                generationJson.put(PeriodTypeEnum.DAY_AFTER.getAlias(),periodFilter.getDay());
                data.put(PaymentEnum.RECEIVABLE_PERIOD.getAttr(), generationJson.toJSONString());
            }
            //初始化其它字段
            for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPayment().entrySet()){
                SaasDataInitHelp.antDataSet(data,entry.getKey(),entry.getValue());
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("paymentAnalyticalServiceImpl.beforeSave error", e);
        }
    }

    /**
     * 覆盖导入时移除不能编辑的字段
     *
     * @param paymentJson 前端传过来的json格式
     * @param dbPaymentJson 存到数据库中的json格式
     * @param businessType 业务类型
     * @param fieldAttrEntity 应收金额的字段解释
     * @param nowModelType 应收款当前所处的模式    1:手动创建应收 2:按开票产生应收 3:按出库产生应收
     * @param modelType 创建应收款时所处的模式
     */
    public void removeUnCoverImportValue(JSONObject paymentJson, JSONObject dbPaymentJson, Integer businessType,Long nowModelType, FieldAttrEntity fieldAttrEntity, Long modelType) {
        List<String> shouldRemoveFieldList = Arrays.asList(PaymentEnum.PAYMENT_NO.getAttr(),
                PaymentEnum.RECEIVABLE_PERIOD.getAttr(), PaymentEnum.SOURCE.getAttr(),
                PaymentEnum.SOURCE_LINK_TEXT.getAttr(), PaymentEnum.CUSTOMER.getAttr(), PaymentEnum.CONTRACT.getAttr(), PaymentEnum.STATUS.getAttr(),
                PaymentEnum.RECEIVABLES_ORIGIN_ID.getAttr(), PaymentEnum.RECEIVABLES_ORIGIN_LINK_TEXT.getAttr(), PaymentEnum.GENERATION_DATE.getAttr());
        //businessType是701 ，nowModelType和modelType都是1时，【回款状态】为未收款且开票金额为0，且表单模版的应收金额字段设置为可编辑。就将应收款的应收金额设置为可编辑
        boolean paymentFlag = Objects.equals(XbbRefTypeEnum.PAYMENT.getCode(), businessType) && Objects.equals(ModelTypeEnum.PLAN.getCode(), nowModelType)
                && Objects.equals(ModelTypeEnum.PLAN.getCode(), modelType)
                && Objects.equals(PaymentStatusEnum.UN_RECEIVABLES.getCode(), dbPaymentJson.getString(PaymentEnum.STATUS.getAttr()))
                && Objects.equals(BasicConstant.ZERO_DOUBLE,dbPaymentJson.getDouble(PaymentEnum.INVOICE_AMOUNT.getAttr()))
                && Objects.nonNull(fieldAttrEntity) && Objects.equals(BasicConstant.ONE, fieldAttrEntity.getEditable());

        ArrayList<String> paymentShouldRemoveFieldList = new ArrayList<>(shouldRemoveFieldList);
        if(!paymentFlag){
            paymentShouldRemoveFieldList.add(PaymentEnum.AMOUNT.getAttr());
        }
        for (String key : dbPaymentJson.keySet()) {
            if (!paymentJson.containsKey(key) || paymentShouldRemoveFieldList.contains(key)) {
                paymentJson.put(key, dbPaymentJson.get(key));
            }
        }

    }

    public AddBatchDTO beforeSaveBatch(FormDataAddDTO formDataSaveDTO, boolean fromApproval) throws XbbException {
        Map<String, Object> params = BeanUtil.convertBean2Map(formDataSaveDTO, true);
        List<PaasFormExplainEntity> explainList = paasFormExplainModel.list(params);
        if (Objects.isNull(explainList) || explainList.isEmpty()) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(explainList.get(0).getExplains(), null);
        JSONObject data = formDataSaveDTO.getDataList();
        JSONArray jsonArray = data.getJSONArray(PaymentEnum.ADD_PAYMENT.getAttr());
        for (Object item : jsonArray) {
            JSONObject jsonObject = (JSONObject) item;
            SaveFormatHelp.dealLabelData(jsonObject.getJSONObject("data"), explainMap);
        }
        data.put(PaymentEnum.ADD_PAYMENT.getAttr(), jsonArray);
        SaveFormatHelp.formatLinkBusiness4SaveByArray(data, PaymentEnum.CUSTOMER.getAttr(), PaymentEnum.CUSTOMER_LINK_TEXT.getAttr(), PaymentEnum.CUSTOMER.getFieldType());
        SaveFormatHelp.formatLinkBusiness4SaveByArray(data, PaymentEnum.CONTRACT.getAttr(), PaymentEnum.CONTRACT_LINK_TEXT.getAttr(), PaymentEnum.CONTRACT.getFieldType());
        Double contractAmount;
        // 来自于合同新建编辑
        Long contractFormId = null;
        Double paymentAmount = 0D;
        Long contractId = null;
        Boolean isNew = false;
        SaasNeedRedundantAttrPojo saasNeedRedundantAttrPoJo = formDataSaveDTO.getSaasNeedRedundantAttrPoJo();
        if (Objects.nonNull(saasNeedRedundantAttrPoJo) && Objects.equals(saasNeedRedundantAttrPoJo.getParentBusinessType(), XbbRefTypeEnum.CONTRACT.getCode())) {
            contractAmount = formDataSaveDTO.getSaasNeedRedundantAttrPoJo().getParentAmount();
            contractFormId = formDataSaveDTO.getSaasNeedRedundantAttrPoJo().getLinkItemFormId();
            isNew = true;
        } else {
            PaasFormDataEntityExt contractEntityExt = contractModel.getByKey(data.getLong(PaymentEnum.CONTRACT.getAttr()),formDataSaveDTO.getCorpid());
            if (Objects.isNull(contractEntityExt)) {
                throw new XbbException(ContractErrorCodeEnum.API_ERROR_203001);
            }
            contractAmount = contractEntityExt.getData().getDouble(ContractEnum.AMOUNT.getAttr());
            contractFormId = contractEntityExt.getFormId();
            contractId = contractEntityExt.getId();
            isNew = false;
        }

        JSONArray paymentArray = data.getJSONArray(PaymentEnum.ADD_PAYMENT.getAttr());
        List<AddMuchFieldPojo> addBatchList = new ArrayList<>();
        List<AddMuchFieldPojo> delBatchList = new ArrayList<>();
        List<AddMuchFieldPojo> updateBatchList = new ArrayList<>();
        List<Object> noChangePaymentList = new ArrayList<>();
        List<ValidateDataDTO> validateDataDTOList = new ArrayList<>();
        List<Long> idIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        FieldAttrEntity serialNoFieldAttr = explainMap.get(PaymentEnum.PAYMENT_NO.getAttr());
        //下面是移除审批中已经删除的回款计划
        fundHelp.handProcessShouldRemoveValue(formDataSaveDTO.getCorpid(), XbbRefTypeEnum.CONTRACT, XbbRefTypeEnum.PAYMENT, paymentArray);
        for (Object obj : paymentArray){
            AddMuchFieldPojo addMuchFieldPojo = new AddMuchFieldPojo();
            ValidateDataDTO validateDataDTO = new ValidateDataDTO();
            JSONObject json = (JSONObject) obj;
            Long dataId = json.getLong(StringConstant.DATA_ID);
            addMuchFieldPojo.setId(dataId);
            String serialNo = json.getString(FieldTypeEnum.SERIALNO.getAlias());
            if (Objects.nonNull(serialNoFieldAttr)) {
                if (Objects.equals(serialNoFieldAttr.getStrictController(), BasicConstant.ONE) && StringUtil.isEmpty(serialNo)) {
                    serialNo = serialNoHelp.getSerialNo(serialNo, formDataSaveDTO.getCorpid(), formDataSaveDTO.getFormId(),  serialNoFieldAttr);
                    json.getJSONObject("data").put(PaymentEnum.PAYMENT_NO.getAttr(),serialNo);
                }
                addMuchFieldPojo.setSerialNo(serialNo);
            }
            if (Objects.nonNull(serialNo) && serialNo.length() > 50) {
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208023);
            }
            JSONObject paymentData = json.getJSONObject("data");
            for (Map.Entry<String,Object> entry : SaasDataInitHelp.initPayment().entrySet()){
                SaasDataInitHelp.antDataSet(paymentData,entry.getKey(),entry.getValue());
            }
            JSONObject statusJSON = FastJsonHelper.getJsonObjectOrDefaultFromFormData(paymentData, PaymentEnum.STATUS.getAttr(),new JSONObject());
            String status = statusJSON.getString("value");
            if ( !Objects.equals(status, PaymentStatusEnum.UN_RECEIVABLES.getCode()) && Objects.isNull(dataId) && Objects.isNull(formDataSaveDTO.getIsOldProgressData())){
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208039, PaymentErrorCodeEnum.API_ERROR_208039.getMsg());
            }
            Integer operationFlag = json.getInteger(StringConstant.OPERATION_FLAG);
            if ( Objects.isNull(dataId) ) {
                operationFlag = null;
            }
            //关联新建和编辑应收款时，未收款状态的应收金额必须大于0
            Double amount = FastJsonHelper.getDoubleOrDefaultFromFormData(paymentData, PaymentEnum.AMOUNT.getAttr(),0D);
            if(Objects.equals(status,PaymentStatusEnum.UN_RECEIVABLES.getCode()) && amount <= BasicConstant.ZERO_DOUBLE){
                throw new XbbException(ImportErrorCodeEnum.API_ERROR_235030);
            }
            if ( !Objects.equals(operationFlag,LinkAddOperationFlagEnum.DEL.getCode()) ) {
                ValidateUtil.validatePayment(paymentData,PaymentEnum.AMOUNT.getAttr(),explainMap);
            }
            paymentData.put(PaymentEnum.CUSTOMER.getAttr(),data.get(PaymentEnum.CUSTOMER.getAttr()));
            paymentData.put(PaymentEnum.CUSTOMER_LINK_TEXT.getAttr(),data.get(PaymentEnum.CUSTOMER_LINK_TEXT.getAttr()));
            paymentData.put(PaymentEnum.CONTRACT.getAttr(),data.get(PaymentEnum.CONTRACT.getAttr()));
            paymentData.put(PaymentEnum.CONTRACT_LINK_TEXT.getAttr(),data.get(PaymentEnum.CONTRACT_LINK_TEXT.getAttr()));
            SaveFormatHelp.formatLinkBusiness4Save(paymentData, PaymentEnum.SOURCE.getAttr(), PaymentEnum.SOURCE_LINK_TEXT.getAttr(), PaymentEnum.SOURCE.getFieldType());

            addMuchFieldPojo.setData(paymentData);

            BeanUtil.copyProperties(formDataSaveDTO,validateDataDTO);
            // validateDataDTO.setSerialNo(json.getString(FieldTypeEnum.SERIALNO.getAlias()));
            validateDataDTO.setBusinessType(XbbRefTypeEnum.PAYMENT.getCode());
            validateDataDTO.setData(addMuchFieldPojo.getData());
            validateDataDTO.setSerialNo(serialNo);
            validateDataDTO.setDataId(dataId);
            validateDataDTO.setFromApproval(fromApproval);
            if (Objects.equals(operationFlag,LinkAddOperationFlagEnum.DEL.getCode())){
                delBatchList.add(addMuchFieldPojo);
                idIn.add(addMuchFieldPojo.getId());
            }else {
                if (Objects.equals(operationFlag,LinkAddOperationFlagEnum.EDIT.getCode())){
                    updateBatchList.add(addMuchFieldPojo);
                    validateDataDTOList.add(validateDataDTO);
                    idIn.add(addMuchFieldPojo.getId());
                    validateTeam(paymentData, validateDataDTO, addMuchFieldPojo, formDataSaveDTO.getDistributorMark());
                }else if (Objects.isNull(dataId)){
                    //普通应收款新建，应收生成日期是当天，应收账期 = 预计回款日期 - 应收生成日期
                    PeriodFilterPojo periodFilter = fundSetHelp.getPeriodFilter4Payment(validateDataDTO.getCorpid(), FastJsonHelper.getLongOrDefaultFromFormData(paymentData,PaymentEnum.ESTIMATE_TIME.getAttr(),0L),
                            null, null, null);
                    JSONObject generationJson = new JSONObject();
                    generationJson.put(BasicConstant.TYPE, PeriodTypeEnum.DAY_AFTER.getCode());
                    generationJson.put(PeriodTypeEnum.DAY_AFTER.getAlias(),periodFilter.getDay());
                    addMuchFieldPojo.getData().put(PaymentEnum.GENERATION_DATE.getAttr(), periodFilter.getGenerationTime());
                    addMuchFieldPojo.getData().put(PaymentEnum.RECEIVABLE_PERIOD.getAttr(), generationJson.toJSONString());
                    addBatchList.add(addMuchFieldPojo);
                    validateDataDTOList.add(validateDataDTO);
                    validateTeam(paymentData, validateDataDTO, addMuchFieldPojo, formDataSaveDTO.getDistributorMark());
                } else {
                    noChangePaymentList.add(obj);
                    idIn.add(addMuchFieldPojo.getId());
                }
                paymentAmount = Arith.add(paymentAmount, FastJsonHelper.getDoubleOrDefaultFromFormData(paymentData, PaymentEnum.AMOUNT.getAttr(), 0D));
            }
            //校验团队负责人之后需要重新变成原来入参的样子，因为这边应收款校验也会走一次这个ProSaveHelp.analyticalData方法
            JSONArray originalOwnerArray = paymentData.getJSONArray(FieldTypeEnum.OWNERID.getAlias());
            JSONArray originalCouserArray = paymentData.getJSONArray(FieldTypeEnum.COUSERID.getAlias());
            validateDataDTO.setExplainMap(explainMap);
            formDataSaveDTO.setExplainMap(explainMap);
            ProSaveHelp.analyticalData(validateDataDTO);
            formDataValidateDataHelp.validateData(validateDataDTO);
            addMuchFieldPojo.setDepartmentId(validateDataDTO.getDepartmentId());
            paymentData.put(FieldTypeEnum.DEPARTMENTID.getAlias(), validateDataDTO.getDepartmentId());
            paymentData.put(FieldTypeEnum.OWNERID.getAlias(), originalOwnerArray);
            paymentData.put(FieldTypeEnum.COUSERID.getAlias(), originalCouserArray);
        }
        //退货退款进来不走这个
        if ((!isNew && contractId != null && contractId != 0L) && !Objects.equals(formDataSaveDTO.getSubBusinessType(),XbbRefTypeEnum.REFUND.getCode())) {
            FormDataUpdateGetDTO formDataUpdateGetDTO = new FormDataUpdateGetDTO();
            BeanUtil.copyProperties(formDataSaveDTO, formDataUpdateGetDTO);
            paymentAmount = Arith.add(paymentAmount,beforeSaveGetTotalAmount(formDataSaveDTO.getCorpid(), contractId, idIn,formDataSaveDTO.getIsTotalPaymentSheetAmount(),formDataUpdateGetDTO));
        }
        if ( paymentAmount < BasicConstant.ZERO_DOUBLE && !Objects.equals(formDataSaveDTO.getSubBusinessType(),XbbRefTypeEnum.REFUND.getCode())) {
            throw new XbbException(ImportErrorCodeEnum.API_ERROR_235030);
        }
        //允许误差小于等于ConfigConstant.amountAccuracy
        if (Arith.sub(paymentAmount, contractAmount) > ConfigConstant.amountAccuracy) {
            throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208002);
        }
        // 只有在合同新建时，需要根据合同开关设置去做金额相等校验
        FormConfigEntity formConfigEntity = formConfigModel.getEntityByFormId(formDataSaveDTO.getCorpid(), contractFormId, FormConfigEnum.CONTRACT_AMOUNT_EQUAL_REPAYMENT_PLAN.getConfig());
        boolean isContractAmountEqualPayment = Objects.equals(FormConfigEnum.CONTRACT_AMOUNT_EQUAL_REPAYMENT_PLAN.getConfigValue(), StringConstant.POSITIVE_NUMBER);
        if ( Objects.nonNull(formConfigEntity) ) {
            if ( Objects.equals(formConfigEntity.getConfigValue(), StringConstant.POSITIVE_NUMBER) ) {
                isContractAmountEqualPayment = true;
            } else {
                isContractAmountEqualPayment = false;
            }
        }
        if ( isContractAmountEqualPayment && (!addBatchList.isEmpty() || !updateBatchList.isEmpty() || !noChangePaymentList.isEmpty()) ) {
            if ( !Objects.equals(paymentAmount, contractAmount) && formDataSaveDTO.getIsTotalPaymentSheetAmount()) {
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208003);
            }
        }
        AddBatchDTO addBatchDTO = new AddBatchDTO();
        BeanUtil.copyProperties(formDataSaveDTO,addBatchDTO);
        addBatchDTO.setAddBatchList(addBatchList);
        FieldAttrEntity serialField = explainMap.getOrDefault(PaymentEnum.PAYMENT_NO.getAttr(), new FieldAttrEntity());
        if (Objects.equals(serialField.getNoRepeat(), 1)) {
            Set<String> addSerialNoSet = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            addBatchList.forEach(addBatch-> addSerialNoSet.add(addBatch.getSerialNo()));
            if (!Objects.equals(addSerialNoSet.size(), addBatchList.size())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.NO_REPEAT, serialField.getAttrName());
            }
        }
        Integer total = addBatchList.size() + updateBatchList.size() - delBatchList.size();
        if ( /*formDataSaveDTO.getIsNew() &&*/ total > StringConstant.MAX_PAYMENT_COUNT ) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.OVER_STEP_MAX_PAYMENT_COUNT, StringConstant.MAX_PAYMENT_COUNT);
        }
        addBatchDTO.setAmount(paymentAmount);
        addBatchDTO.setUpdateBatchList(updateBatchList);
        addBatchDTO.setDelBatchList(delBatchList);
        addBatchDTO.setValidateDataDTOList(validateDataDTOList);
        return addBatchDTO;
    }

    /**
     * 校验团队并且往参数中封装团队信息
     *
     * @param json
     * @param validateDataDTO
     * @param addMuchFieldPojo
     * @param distributorMark 经销商标识
     */
    private void validateTeam(JSONObject json, ValidateDataDTO validateDataDTO, AddMuchFieldPojo addMuchFieldPojo, Integer distributorMark) throws XbbException {
        if (Objects.equals(distributorMark, DistributorMarkEnum.DISTRIBUTOR.getCode())) {
            return;
        }
        //因为合同批量新建应收款的时候，validateDataDTO最外层也有合同的负责任人、协同人，所以需要把最外层的先移除掉
        validateDataDTO.setOwnerIds(null);
        validateDataDTO.setCoUserId(null);
        JSONArray teamMainPojoArray = json.getJSONArray(FieldTypeEnum.OWNERID.getAlias());
        JSONArray teamCoPojoArray = json.getJSONArray(FieldTypeEnum.COUSERID.getAlias());
        if (Objects.nonNull(teamMainPojoArray) && teamMainPojoArray.size() > BasicConstant.ZERO) {
            List<ReturnUserAndDepartmentPojo> ownerIds = JSON.parseArray(JSON.toJSONString(teamMainPojoArray), ReturnUserAndDepartmentPojo.class);
            validateDataDTO.setOwnerIds(ownerIds);
        }
        if (Objects.nonNull(teamCoPojoArray) && teamCoPojoArray.size() > BasicConstant.ZERO) {
            List<ReturnUserAndDepartmentPojo> coUserIds = JSON.parseArray(JSON.toJSONString(teamCoPojoArray), ReturnUserAndDepartmentPojo.class);
            validateDataDTO.setCoUserId(coUserIds);
        }
        try{
            teamUserHelp.beforeVerifyUserTeam(validateDataDTO);
        }catch (XbbException e){
            throw new XbbException(e.getCode(), teamUserHelp.formatErrorMessage(e.getCode(), e.getMsg(), XbbRefTypeEnum.PAYMENT));
        }
        TeamAfterVerifyDTO teamAfterVerifyDTO = validateDataDTO.getSaasNeedRedundantAttrPoJo().getTeamAfterVerifyDTO();
        addMuchFieldPojo.setTeamAfterVerifyDTO(teamAfterVerifyDTO);
    }

    /**
     *　合同"未收金额"
     *　回款计划的"计划收款金额"（销项发票开票金额，销售出库金额）
     *　合同金额-已生成的应收金额
     * @param corpid
     * @param contractId
     * @param idIn
     * @param isTotalPaymentSheet
     * @param formDataUpdateGetDTO
     * @return
     * @throws XbbException
     */
    public Double beforeSaveGetTotalAmount(String corpid, Long contractId, List<Long> idIn, Boolean isTotalPaymentSheet,FormDataUpdateGetDTO formDataUpdateGetDTO) throws XbbException {
        Double paymentAmount = 0D;
        List<AggSumDTO> sumList = new ArrayList<>();
        AggSumDTO aggSumDTO = new AggSumDTO();
        aggSumDTO.setAttr(PaymentEnum.AMOUNT.getAttr());
        aggSumDTO.setField(PaymentEnum.getAttrConnectData(PaymentEnum.AMOUNT));
        sumList.add(aggSumDTO);
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery(ParameterConstant.CORPID, corpid));
        boolQueryBuilder.filter(termQuery(ParameterConstant.DEL, DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery(PaymentEnum.getEsAttr4Keyword(PaymentEnum.CONTRACT), contractId));
        if ( !idIn.isEmpty() ) {
            boolQueryBuilder.filter(boolQuery().mustNot(termsQuery(BasicConstant.DATAID, idIn)));
        }
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
        NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();
        IndexTypeEnum indexTypeEnum = IndexTypeEnum.IDX_SAAS_PAYMENT;

        List<AggSumVO> aggSumList = esHelper.aggSumByField(indexTypeEnum.getIndex(), indexTypeEnum.getType(), sumList, searchQuery);
        for ( AggSumVO aggSumVO : aggSumList ) {
            if ( PaymentEnum.AMOUNT.getAttr().equals(aggSumVO.getAttr()) ) {
                Double amount = aggSumVO.getValue() == null ? 0D : Double.parseDouble(aggSumVO.getValue().toString());
                paymentAmount = Arith.add(paymentAmount, amount);
            }
        }
        if ( Objects.nonNull(isTotalPaymentSheet) && isTotalPaymentSheet ) {
            formDataUpdateGetDTO.setDataId(contractId);
            paymentAmount = fundMoneyHelp.getCheckAmount(formDataUpdateGetDTO,XbbRefTypeEnum.CONTRACT.getCode(),paymentAmount);
        }
        return paymentAmount;
    }
}
